package com.egzosn.infrastructure.database.jdbc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.util.Assert;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Insert adapter for InsertPreparedStatementCreator, allowing to use a plain SQL statement.
 */
public class PreparedStatementCreator implements org.springframework.jdbc.core.PreparedStatementCreator, SqlProvider {

    private static Logger logger = LoggerFactory.getLogger(PreparedStatementCreator.class);

    private final String sql;
    /**
     * a flag indicating whether auto-generated keys
     *        should be returned; one of
     *        <code>Statement.RETURN_GENERATED_KEYS</code> or
     *        <code>Statement.NO_GENERATED_KEYS</code>
     */
    private final int autoGeneratedKey;
    /**
     *
     */
    private final Object[] args;
    /**
     * is batch
     */
    private  boolean isBatch = false;
    /**
     * Successful record number
     */
    private int rowCont = 0;

    /**
     *
     * @param sql an SQL statement that may contain one or more '?' IN
     *        parameter placeholders
     * @param args sql  more '?' IN parameter
     * @param autoGeneratedKey      a flag indicating whether auto-generated keys
     *        should be returned; one of
     *        true <code>Statement.RETURN_GENERATED_KEYS</code> or
     *        false <code>Statement.NO_GENERATED_KEYS</code>
     */
    public PreparedStatementCreator(String sql, boolean autoGeneratedKey, Object... args) {
        Assert.notNull(sql, "SQL must not be null");
        this.sql = sql;
        this.autoGeneratedKey = autoGeneratedKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS ;
        this.args = args;
    }
    /**
     *
     * @param sql an SQL statement that may contain one or more '?' IN
     *        parameter placeholders
     * @param args sql  more '?' IN parameter
     * @param autoGeneratedKey      a flag indicating whether auto-generated keys
     *        should be returned; one of
     *        true <code>Statement.RETURN_GENERATED_KEYS</code> or
     *        false <code>Statement.NO_GENERATED_KEYS</code>
     */
    public PreparedStatementCreator(String sql, boolean autoGeneratedKey, Object[]... args) {
        this(sql, autoGeneratedKey, (Object[]) args);
    }


    /**
     *
     * @param sql an SQL statement that may contain one or more '?' IN
     *        parameter placeholders
     * @param args sql  more '?' IN parameter
     */
    public PreparedStatementCreator(String sql, Object... args) {
        this(sql, false, args);
    }
    /**
     *
     * @param sql an SQL statement that may contain one or more '?' IN
     *        parameter placeholders
     * @param args sql  more '?' IN parameter
     */
    public PreparedStatementCreator(String sql, Object[]... args) {
        this(sql, (Object[])args);
    }
    /**
     *
     * @param sql an SQL statement that may contain one or more '?' IN
     *        parameter placeholders
     */
    public PreparedStatementCreator(String sql) {
        this(sql, null);
    }


    @Override
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
        PreparedStatement ps = con.prepareStatement(this.sql, autoGeneratedKey);

        if (null != args){
            SQLTools.fillStatement(ps, args);
            if (isBatch  && (rowCont = args.length) > 0){
                int success = ps.executeBatch().length ;
                if (success > 0 && success < rowCont){
                    logger.warn("The number of successful {}, now successful {} ", rowCont, success );
                }
                rowCont = success;
            }else {
                rowCont = ps.executeUpdate();
            }
            if (rowCont < 1) {
                throw new SQLException("sql:{} On failure.", ps.toString());
            }
        }

        return ps;
    }

    @Override
    public String getSql() {
        return this.sql;
    }

    public int getRowCont() {
        return rowCont;
    }
}